package com.wontube.core.srv;

import java.util.ArrayList;
import java.util.HashMap;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.wontube.core.utils.ClassUtils;


/**
 * @author yuechao
 * 
 *         服务管理器
 */
public final class ServiceManager {
	private static final Logger logger = LoggerFactory.getLogger(ServiceManager.class);

	private ServiceManager() {
	}

	// 服务器列表
	private static final ArrayList<IService> listService = new ArrayList<IService>();

	// 服务名到服务本身的映射
	private static final HashMap<String, IService> serviceMap = new HashMap<String, IService>();

	// 经常使用的服务接口类型实现的缓存
	private static final HashMap<Class<?>, IService> serviceMapCache = new HashMap<Class<?>, IService>();

	// 标记是否已经初始化
	private static boolean isInitialized = false;

	// 获取指定名称的服务
	public static IService get(String name) {
		return serviceMap.get(name);
	}

	// 获取指定类型的服务
	@SuppressWarnings("unchecked")
	public static <A extends IService> A get(Class<A> cls) {
		A service = (A) serviceMapCache.get(cls);
		if (service == null) {
			for (IService item : listService) {
				if (cls.isAssignableFrom(item.getClass())) {
					service = (A) item;
					serviceMapCache.put(cls, service);
					break;
				}
			}
		}

		return service;
	}

	/**
	 * 初始化系统服务
	 */
	public static void startup() {
		if (isInitialized) {
			return;
		}

		isInitialized = true;
		listService.clear();
		serviceMap.clear();
		serviceMapCache.clear();

		logger.info("begins loading service classes");

		// 加载服务
		try {
			for (Class<IService> cls : ClassUtils.loadSubClasses(IService.class)) {
				IService service = cls.newInstance();
				serviceMap.put(service.name(), service);
				listService.add(service);
			}
		} catch (Exception e) {
			logger.error(e.toString());
			isInitialized = false;
			return;
		}

		// 对服务进行排序
		new ServiceSorter().sort(listService);

		// 启动所有服务
		for (IService obj : listService) {
			obj.startup();
			logger.info("service startup [" + obj.getClass().getName() + ']');
		}

		logger.info("finish loading service classes");
	}

	/**
	 * 关闭所有服务
	 */
	public static void shutdown() {
		for (int i = listService.size() - 1; i >= 0; i--) {
			IService obj = listService.get(i);
			obj.shutdown();
			logger.info("service shutdown [" + obj.getClass().getName() + ']');
		}

		isInitialized = false;
	}

	/**
	 * 优先级比较. 排在前面的优先启动
	 */
	private static class ServiceSorter {
		/**
		 * 结果列表
		 */
		private ArrayList<IService> listResult = new ArrayList<IService>();

		/**
		 * 源列表
		 */
		private ArrayList<IService> listSource = new ArrayList<IService>();

		/**
		 * 按依赖关系对服务对像进行排序
		 */
		public void sort(ArrayList<IService> lst) {
			this.listSource = lst;
			for (IService obj : this.listSource) {
				this.append(obj);
			}

			lst.clear();
			lst.addAll(this.listResult);
		}

		/**
		 * 将服务加入到结果列表
		 * 
		 * @param obj
		 */
		private void append(IService obj) {
			Class<?>[] depends = obj.depends();
			if (depends != null && depends.length > 0) {
				for (Class<?> cls : depends) {
					IService parent = this.find(cls);
					if (parent != null) {
						this.append(parent);
					}
				}
			}

			if (!this.listResult.contains(obj)) {
				listResult.add(obj);
			}
		}

		/**
		 * 查找指定类型的子类
		 * 
		 * @param cls
		 * @return
		 */
		private IService find(Class<?> cls) {
			for (IService obj : this.listSource) {
				if (cls.isAssignableFrom(obj.getClass())) {
					return obj;
				}
			}

			return null;
		}
	}

	// 检查所有服务是否正常运行
	public static void diagnose() {
		ArrayList<IService> lst = new ArrayList<IService>();
		for (int i = listService.size() - 1; i >= 0; i--) {
			IService obj = listService.get(i);
			if (!obj.isAlive()) {
				logger.warn("service dead [" + obj.getClass().getName() + ']');
				obj.shutdown();
				lst.add(obj);
			}
		}

		// 重启服务
		for (IService obj : lst) {
			obj.startup();
			logger.warn("service restart [" + obj.getClass().getName() + ']');
		}
	}
}
